
要理解 TypeScript 函式多載的概念,可以把它想像成生活中我們常見的「同一種行為有多種執行方式」的情境。
以下是一些日常例子,幫助你更直觀地理解這個技術:
點餐系統的應用:
order 函數有多種不同的參數組合和調用方式,這些多載的簽名就像不同的點餐方式,最終都是為了完成點餐這個任務。function order(dish: string): void // 口頭點餐
function order(dish: string, extras: string[]): void // 加點配料
function order(dish: string, callback: (confirmation: string) => void): void // 使用回呼函數
搜尋產品:
search 函數的多載簽名像是給搜尋行為添加不同的功能層次。function search(term: string): Promise<Product[]> // 簡單搜尋
function search(term: string, filters: string[]): Promise<Product[]> // 帶篩選條件
function search(term: string, callback: (products: Product[]) => void, filters?: string[]): void // 搜尋結果後觸發通知
約會提醒:
remind 函數可以根據不同參數組合以不同方式執行提醒。function remind(person: string, method: "message"): void // 發訊息
function remind(person: string, method: "calendar"): void // 日曆提醒
function remind(person: string, method: "email"): void // 寄電子郵件
**函式多載 Function Overloading ** 的核心是:同一個行為或操作,根據情況使用不同的「方式」來實現,讓程式碼變得靈活且符合實際需求。
在 TypeScript 中,函式多載 (Function Overloading) 允許為函數定義多個簽名(signatures),每個簽名可以有不同的參數類型和返回類型。這在需要提供多種方式調用函數的情況下非常實用,同時還能保持類型安全。以下,我們將透過一個實際的例子探討函式多載的使用。
在以下程式碼中,我們有一個 search 函數,具有三個不同的多載簽名:
type Result = {
  title: string,
  url: string,
  abstract: string
}
// 第一個多載:返回 Result 陣列的 Promise
function search(
  term: string,
  tags?: string[]
): Promise<Result[]>
// 第二個多載:接受回呼函數並返回 void
function search(
  term: string,
  callback: (results: Result[]) => void,
  tags?: string[]
): void
// 實際實現,包含所有可能的參數組合
function search(
  term: string,
  p2?: string[] | ((results: Result[]) => void),
  p3?: string[]
) {
  // 判斷 p2 是否為回呼函數
  const callback = 
    typeof p2 === 'function' ? p2 : undefined
  // 判斷是否提供了 tags
  const tags = 
    typeof p2 !== 'undefined' && Array.isArray(p2) ? p2 :
    typeof p3 !== 'undefined' && Array.isArray(p3) ? p3 : 
    undefined;
 
  let queryString = `?query=${term}`
  if (tags && tags.length) {
    queryString += `&tags=${tags.join()}`
  }
  // 向伺服器請求搜尋結果
  const results = fetch(`/search${queryString}`)
    .then(response => response.json())
  // 如果有提供回呼函數則使用它,否則返回 Promise
  if (callback) {
    results.then(res => callback(res))
    return
  } else {
    return results
  }
}
函數簽名與載:
search,並返回解析為 Result 陣列的 Promise。search,不返回任何值,而是直接透過回呼處理搜尋結果。實現細節:
p2) 是回呼函數還是 tags 陣列。p2 是函數,則將其視為回呼;如果 p2 或 p3 是陣列,則視為 tags。根據參數執行不同邏輯:
search 將獲取結果並將其傳遞給回呼函數,而不返回任何東西,符合第二個多載的 void 返回類型。Promise,符合第一個多載的 Promise<Result[]> 返回類型。返回 Promise:
search("TypeScript", ["programming", "language"])
  .then(results => {
    console.log(results);
  });
使用回呼函數:
search("TypeScript", (results) => {
  console.log(results);
}, ["programming", "language"]);
在這些範例中,你可以看到函式多載如何提供兩種不同的方式來使用 search 函數,取決於所需的行為。
TypeScript 的函式多載是程式碼世界的萬能膠!要發揮它的最大威力,以下幾點正確姿勢你一定要知道:
精準定義多載簽名:每個多載簽名都應該清楚地反映出不同的使用情境,避免讓人搞不清楚該用哪種方式調用函數。
避免濫用:雖然多載超好用,但也別為了多載而多載,確保每個多載都是真正需要的,避免讓程式碼變成難以維護的怪獸。
保持一致性:實現的函數體要能支持所有多載簽名,確保每種調用方式都能正常運行,不然會掉入意料之外的坑裡!
善用類型守衛:透過 TypeScript 的類型守衛來區分不同的參數組合,讓你的多載實現更清晰、更穩定。
加強可讀性與維護性:多載的目的是讓程式碼易讀、好維護,不要把邏輯寫得過於複雜,記住我們的目標是清楚簡潔!
正確使用 TypeScript 函式多載,可以讓你的程式碼靈活應對不同的需求,寫得更漂亮、更專業。
像我們的 search 函數一樣,輕鬆面對各種參數組合,實現更豐富的功能吧!٩(^ᴗ^)۶